home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / Misc / SysEnum / SysEnumDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  17.7 KB  |  655 lines

  1. //------------------------------------------------------------------------------
  2. // File: SysEnumDlg.cpp
  3. //
  4. // Desc: DirectShow sample code - implementation of dialog for device
  5. //       enumeration.
  6. //
  7. // Copyright (c) 2000-2001 Microsoft Corporation.  All rights reserved.
  8. //------------------------------------------------------------------------------
  9.  
  10.  
  11. #include "stdafx.h"
  12. #include <atlbase.h>
  13. #include "SysEnum.h"
  14. #include "SysEnumDlg.h"
  15.  
  16. #ifdef _DEBUG
  17. #define new DEBUG_NEW
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CAboutDlg dialog used for App About
  24.  
  25. class CAboutDlg : public CDialog
  26. {
  27. public:
  28.     CAboutDlg();
  29.  
  30. // Dialog Data
  31.     //{{AFX_DATA(CAboutDlg)
  32.     enum { IDD = IDD_ABOUTBOX };
  33.     //}}AFX_DATA
  34.  
  35.     // ClassWizard generated virtual function overrides
  36.     //{{AFX_VIRTUAL(CAboutDlg)
  37.     protected:
  38.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  39.     //}}AFX_VIRTUAL
  40.  
  41. // Implementation
  42. protected:
  43.     //{{AFX_MSG(CAboutDlg)
  44.     //}}AFX_MSG
  45.     DECLARE_MESSAGE_MAP()
  46. };
  47.  
  48. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  49. {
  50.     //{{AFX_DATA_INIT(CAboutDlg)
  51.     //}}AFX_DATA_INIT
  52. }
  53.  
  54. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  55. {
  56.     CDialog::DoDataExchange(pDX);
  57.     //{{AFX_DATA_MAP(CAboutDlg)
  58.     //}}AFX_DATA_MAP
  59. }
  60.  
  61. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  62.     //{{AFX_MSG_MAP(CAboutDlg)
  63.         // No message handlers
  64.     //}}AFX_MSG_MAP
  65. END_MESSAGE_MAP()
  66.  
  67. /////////////////////////////////////////////////////////////////////////////
  68. // CSysEnumDlg dialog
  69.  
  70. CSysEnumDlg::CSysEnumDlg(CWnd* pParent /*=NULL*/)
  71.     : CDialog(CSysEnumDlg::IDD, pParent)
  72. {
  73.     //{{AFX_DATA_INIT(CSysEnumDlg)
  74.     m_bShowAllCategories = FALSE;
  75.     //}}AFX_DATA_INIT
  76.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  77.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  78. }
  79.  
  80. void CSysEnumDlg::DoDataExchange(CDataExchange* pDX)
  81. {
  82.     CDialog::DoDataExchange(pDX);
  83.     //{{AFX_DATA_MAP(CSysEnumDlg)
  84.     DDX_Control(pDX, IDC_STATIC_FILENAME, m_StrFilename);
  85.     DDX_Control(pDX, IDC_STATIC_FILTERS, m_StrFilters);
  86.     DDX_Control(pDX, IDC_STATIC_CLASSES, m_StrClasses);
  87.     DDX_Control(pDX, IDC_LIST_FILTERS, m_FilterList);
  88.     DDX_Control(pDX, IDC_LIST_DEVICES, m_DeviceList);
  89.     DDX_Check(pDX, IDC_CHECK_SHOWALL, m_bShowAllCategories);
  90.     //}}AFX_DATA_MAP
  91. }
  92.  
  93. BEGIN_MESSAGE_MAP(CSysEnumDlg, CDialog)
  94.     //{{AFX_MSG_MAP(CSysEnumDlg)
  95.     ON_WM_SYSCOMMAND()
  96.     ON_WM_PAINT()
  97.     ON_WM_QUERYDRAGICON()
  98.     ON_LBN_SELCHANGE(IDC_LIST_DEVICES, OnSelchangeListDevices)
  99.     ON_WM_CLOSE()
  100.     ON_BN_CLICKED(IDC_CHECK_SHOWALL, OnCheckShowall)
  101.     ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
  102.     //}}AFX_MSG_MAP
  103. END_MESSAGE_MAP()
  104.  
  105.  
  106. /////////////////////////////////////////////////////////////////////////////
  107. // CSysEnumDlg message handlers
  108.  
  109. void CSysEnumDlg::OnSysCommand(UINT nID, LPARAM lParam)
  110. {
  111.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  112.     {
  113.         CAboutDlg dlgAbout;
  114.         dlgAbout.DoModal();
  115.     }
  116.     else
  117.     {
  118.         CDialog::OnSysCommand(nID, lParam);
  119.     }
  120. }
  121.  
  122.  
  123. // If you add a minimize button to your dialog, you will need the code below
  124. //  to draw the icon.  For MFC applications using the document/view model,
  125. //  this is automatically done for you by the framework.
  126.  
  127. void CSysEnumDlg::OnPaint() 
  128. {
  129.     if (IsIconic())
  130.     {
  131.         CPaintDC dc(this); // device context for painting
  132.  
  133.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  134.  
  135.         // Center icon in client rectangle
  136.         int cxIcon = GetSystemMetrics(SM_CXICON);
  137.         int cyIcon = GetSystemMetrics(SM_CYICON);
  138.         CRect rect;
  139.         GetClientRect(&rect);
  140.         int x = (rect.Width() - cxIcon + 1) / 2;
  141.         int y = (rect.Height() - cyIcon + 1) / 2;
  142.  
  143.         // Draw the icon
  144.         dc.DrawIcon(x, y, m_hIcon);
  145.     }
  146.     else
  147.     {
  148.         CDialog::OnPaint();
  149.     }
  150. }
  151.  
  152. // The system calls this to obtain the cursor to display while the user drags
  153. //  the minimized window.
  154. HCURSOR CSysEnumDlg::OnQueryDragIcon()
  155. {
  156.     return (HCURSOR) m_hIcon;
  157. }
  158.  
  159.  
  160. BOOL CSysEnumDlg::OnInitDialog()
  161. {
  162.     HRESULT hr;
  163.  
  164.     CDialog::OnInitDialog();
  165.  
  166.     // Add "About..." menu item to system menu.
  167.  
  168.     // IDM_ABOUTBOX must be in the system command range.
  169.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  170.     ASSERT(IDM_ABOUTBOX < 0xF000);
  171.  
  172.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  173.     if (pSysMenu != NULL)
  174.     {
  175.         CString strAboutMenu;
  176.         strAboutMenu.LoadString(IDS_ABOUTBOX);
  177.         if (!strAboutMenu.IsEmpty())
  178.         {
  179.             pSysMenu->AppendMenu(MF_SEPARATOR);
  180.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  181.         }
  182.     }
  183.  
  184.     // Set the icon for this dialog.  The framework does this automatically
  185.     //  when the application's main window is not a dialog
  186.     SetIcon(m_hIcon, TRUE);            // Set big icon
  187.     SetIcon(m_hIcon, FALSE);        // Set small icon
  188.     
  189.     ////////////////////////////////////////////////////////////////////////
  190.     //
  191.     //  DirectShow-specific initialization code
  192.  
  193.     CoInitialize(NULL);
  194.  
  195.     // Instantiate the system device enumerator
  196.     m_pSysDevEnum = NULL;
  197.  
  198.     hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, 
  199.                           CLSCTX_INPROC, IID_ICreateDevEnum, 
  200.                           (void **)&m_pSysDevEnum);
  201.     if FAILED(hr)
  202.     {
  203.         CoUninitialize();
  204.         return FALSE;
  205.     }
  206.  
  207.     // By default, only enumerate subset of categories listed in docs
  208.     m_bShowAllCategories = FALSE;
  209.     FillCategoryList();
  210.  
  211.     return TRUE;  // return TRUE  unless you set the focus to a control
  212. }
  213.  
  214.  
  215. void CSysEnumDlg::OnCheckShowall() 
  216. {
  217.     // Toggle category type and redraw the category list
  218.     m_bShowAllCategories ^= 1;
  219.     FillCategoryList();
  220.     SetNumFilters(0);
  221. }
  222.  
  223.  
  224. void CSysEnumDlg::FillCategoryList(void)
  225. {
  226.     // Clear listboxes
  227.     ClearDeviceList();
  228.     ClearFilterList();
  229.  
  230.     if (m_bShowAllCategories)
  231.     {
  232.         // Emulate the behavior of GraphEdit by enumerating all 
  233.         // categories in the system
  234.         DisplayFullCategorySet();
  235.     }
  236.     else
  237.     {
  238.         // Fill the category list box with the categories to display,
  239.         // using the names stored in the CATEGORY_INFO array.
  240.         // SysEnumDlg.H for a category description.
  241.         for (int i=0; i < NUM_CATEGORIES; i++)
  242.         {
  243.             m_DeviceList.AddString(categories[i].szName);
  244.         }
  245.  
  246.         // Update listbox title with number of classes
  247.         SetNumClasses(NUM_CATEGORIES);
  248.     }
  249. }
  250.  
  251.  
  252. void CSysEnumDlg::SetNumClasses(int nClasses)
  253. {
  254.     TCHAR szClasses[64];
  255.  
  256.     wsprintf(szClasses, TEXT("%s (%d found)\0"), STR_CLASSES, nClasses);
  257.     m_StrClasses.SetWindowText(szClasses);
  258. }
  259.  
  260. void CSysEnumDlg::SetNumFilters(int nFilters)
  261. {
  262.     TCHAR szFilters[64];
  263.  
  264.     if (nFilters)
  265.         wsprintf(szFilters, TEXT("%s (%d found)\0"), STR_FILTERS, nFilters);
  266.     else
  267.         wsprintf(szFilters, TEXT("%s\0"), STR_FILTERS);
  268.  
  269.     m_StrFilters.SetWindowText(szFilters);
  270. }
  271.  
  272.  
  273. void CSysEnumDlg::DisplayFullCategorySet(void)
  274. {
  275.     USES_CONVERSION;
  276.  
  277.     HRESULT hr;
  278.     IEnumMoniker *pEmCat = 0;
  279.     ICreateDevEnum *pCreateDevEnum = NULL;
  280.     int nClasses=0;
  281.  
  282.     // Create an enumerator
  283.     hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
  284.                           IID_ICreateDevEnum, (void**)&pCreateDevEnum);
  285.     ASSERT(SUCCEEDED(hr));
  286.     if (FAILED(hr))
  287.         return;
  288.  
  289.     // Use the meta-category that contains a list of all categories.
  290.     // This emulates the behavior of GraphEdit.
  291.     hr = pCreateDevEnum->CreateClassEnumerator(
  292.                          CLSID_ActiveMovieCategories, &pEmCat, 0);
  293.     ASSERT(SUCCEEDED(hr));
  294.  
  295.     if(hr == S_OK)
  296.     {
  297.         IMoniker *pMCat;
  298.         ULONG cFetched;
  299.  
  300.         // Enumerate over every category
  301.         while(hr = pEmCat->Next(1, &pMCat, &cFetched),
  302.               hr == S_OK)
  303.         {
  304.             IPropertyBag *pPropBag;
  305.  
  306.             // Associate moniker with a file
  307.             hr = pMCat->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
  308.             if(SUCCEEDED(hr))
  309.             {
  310.                 VARIANT varCatClsid;
  311.                 varCatClsid.vt = VT_BSTR;
  312.  
  313.                 // Read CLSID string from property bag
  314.                 hr = pPropBag->Read(L"CLSID", &varCatClsid, 0);
  315.                 if(SUCCEEDED(hr))
  316.                 {
  317.                     CLSID clsidCat;
  318.  
  319.                     if(CLSIDFromString(varCatClsid.bstrVal, &clsidCat) == S_OK)
  320.                     {
  321.                         // Use the guid if we can't get the name
  322.                         WCHAR *wszCatName;
  323.                         TCHAR szCatDesc[MAX_PATH];
  324.  
  325.                         VARIANT varCatName;
  326.                         varCatName.vt = VT_BSTR;
  327.  
  328.                         // Read filter name
  329.                         hr = pPropBag->Read(L"FriendlyName", &varCatName, 0);
  330.                         if(SUCCEEDED(hr))
  331.                             wszCatName = varCatName.bstrVal;
  332.                         else
  333.                             wszCatName = varCatClsid.bstrVal;
  334.  
  335. #ifndef UNICODE
  336.                         WideCharToMultiByte(
  337.                                 CP_ACP, 0, wszCatName, -1,
  338.                                 szCatDesc, sizeof(szCatDesc), 0, 0);
  339. #else
  340.                         lstrcpy(szCatDesc, W2T(wszCatName));
  341. #endif
  342.  
  343.                         if(SUCCEEDED(hr))
  344.                             SysFreeString(varCatName.bstrVal);
  345.  
  346.                         // Add category name and CLSID to list box
  347.                         AddFilterCategory(szCatDesc, &clsidCat);
  348.                         nClasses++;
  349.                     }
  350.  
  351.                     SysFreeString(varCatClsid.bstrVal);
  352.                 }
  353.  
  354.                 pPropBag->Release();
  355.             }
  356.             else
  357.             {
  358.                 break;
  359.             }
  360.  
  361.             pMCat->Release();
  362.         } // for loop
  363.  
  364.         pEmCat->Release();
  365.     }
  366.  
  367.     pCreateDevEnum->Release();
  368.  
  369.     // Update listbox title with number of classes
  370.     SetNumClasses(nClasses);
  371. }
  372.  
  373.  
  374. void CSysEnumDlg::AddFilterCategory(
  375.     const TCHAR *szCatDesc,
  376.     const GUID *pCatGuid)
  377. {
  378.     // Allocate a new CLSID, whose pointer will be stored in 
  379.     // the listbox.  When the listbox is cleared, these will be deleted.
  380.     CLSID *pclsid = new CLSID;
  381.     if (pclsid)
  382.         *pclsid = *pCatGuid;
  383.  
  384.     // Add the category name and a pointer to its CLSID to the list box
  385.     int nSuccess  = m_DeviceList.AddString(szCatDesc);
  386.     int nIndexNew = m_DeviceList.FindStringExact(-1, szCatDesc);
  387.     nSuccess = m_DeviceList.SetItemDataPtr(nIndexNew, pclsid);
  388. }
  389.  
  390. void CSysEnumDlg::AddFilter(
  391.     const TCHAR *szFilterName,
  392.     const GUID *pCatGuid)
  393. {
  394.     // Allocate a new CLSID, whose pointer will be stored in 
  395.     // the listbox.  When the listbox is cleared, these will be deleted.
  396.     CLSID *pclsid = new CLSID;
  397.     if (pclsid)
  398.         *pclsid = *pCatGuid;
  399.  
  400.     // Add the category name and a pointer to its CLSID to the list box
  401.     int nSuccess  = m_FilterList.AddString(szFilterName);
  402.     int nIndexNew = m_FilterList.FindStringExact(-1, szFilterName);
  403.     nSuccess = m_FilterList.SetItemDataPtr(nIndexNew, pclsid);
  404. }
  405.  
  406.  
  407. void CSysEnumDlg::ClearDeviceList(void)
  408. {
  409.     CLSID *pStoredId = NULL;
  410.     
  411.     int nCount = m_DeviceList.GetCount();
  412.  
  413.     // Delete any CLSID pointers that were stored in the listbox item data
  414.     for (int i=0; i < nCount; i++)
  415.     {
  416.         pStoredId = (CLSID *) m_DeviceList.GetItemDataPtr(i);
  417.         if (pStoredId != 0)
  418.         {
  419.             delete pStoredId;
  420.             pStoredId = NULL;
  421.         }
  422.     }
  423.  
  424.     // Clean up
  425.     m_DeviceList.ResetContent();
  426.     SetNumClasses(0);
  427. }
  428.  
  429. void CSysEnumDlg::ClearFilterList(void)
  430. {
  431.     CLSID *pStoredId = NULL;
  432.     
  433.     int nCount = m_FilterList.GetCount();
  434.  
  435.     // Delete any CLSID pointers that were stored in the listbox item data
  436.     for (int i=0; i < nCount; i++)
  437.     {
  438.         pStoredId = (CLSID *) m_FilterList.GetItemDataPtr(i);
  439.         if (pStoredId != 0)
  440.         {
  441.             delete pStoredId;
  442.             pStoredId = NULL;
  443.         }
  444.     }
  445.  
  446.     // Clean up
  447.     m_FilterList.ResetContent();
  448.     SetNumFilters(0);
  449.     m_StrFilename.SetWindowText(TEXT("<No filter selected>"));
  450. }
  451.  
  452.  
  453. void CSysEnumDlg::OnSelchangeListDevices() 
  454. {
  455.     HRESULT hr;    
  456.     IEnumMoniker *pEnumCat = NULL;
  457.  
  458.     // Get the currently selected category name
  459.     int nItem = m_DeviceList.GetCurSel();
  460.     const CLSID *clsid;
  461.     
  462.     if (m_bShowAllCategories)
  463.     {
  464.         // Read the CLSID pointer from the list box's item data
  465.         clsid = (CLSID *) m_DeviceList.GetItemDataPtr(nItem);
  466.     }
  467.     else
  468.     {
  469.         // Read the CLSID pointer from our hard-coded array of
  470.         // documented filter categories
  471.         clsid = categories[nItem].pclsid;
  472.     }
  473.  
  474.     // If the CLSID wasn't allocated earlier, then fail
  475.     if (!clsid)
  476.     {
  477.         MessageBeep(0);
  478.         return;
  479.     }
  480.  
  481.     //
  482.     // WARNING!
  483.     //
  484.     // Some third-party filters throw an exception (int 3) during enumeration
  485.     // on Debug builds, often due to heap corruption in RtlFreeHeap().
  486.     // This is not an issue on Release builds.
  487.     //
  488.  
  489.     // Enumerate all filters of the selected category  
  490.     hr = m_pSysDevEnum->CreateClassEnumerator(*clsid, &pEnumCat, 0);
  491.     ASSERT(SUCCEEDED(hr));
  492.     if FAILED(hr)
  493.         return;
  494.  
  495.     // Enumerate all filters using the category enumerator
  496.     hr = EnumFilters(pEnumCat);
  497.  
  498.     SAFE_RELEASE(pEnumCat);
  499. }
  500.  
  501.  
  502. HRESULT CSysEnumDlg::EnumFilters(IEnumMoniker *pEnumCat)
  503. {
  504.     HRESULT hr=S_OK;
  505.     IMoniker *pMoniker;
  506.     ULONG cFetched;
  507.     VARIANT varName={0};
  508.     int nFilters=0;
  509.  
  510.     // Clear the current filter list
  511.     ClearFilterList();
  512.  
  513.     // If there are no filters of a requested type, show default string
  514.     if (!pEnumCat)
  515.     {
  516.         m_FilterList.AddString(TEXT("<< No entries >>"));
  517.         SetNumFilters(nFilters);
  518.         return S_FALSE;
  519.     }
  520.  
  521.     // Enumerate all items associated with the moniker
  522.     while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
  523.     {
  524.         IPropertyBag *pPropBag;
  525.         ASSERT(pMoniker);
  526.  
  527.         // Associate moniker with a file
  528.         hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 
  529.                                     (void **)&pPropBag);
  530.         ASSERT(SUCCEEDED(hr));
  531.         ASSERT(pPropBag);
  532.         if (FAILED(hr))
  533.             continue;
  534.  
  535.         // Read filter name from property bag
  536.         varName.vt = VT_BSTR;
  537.         hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  538.         if (FAILED(hr))
  539.             continue;
  540.  
  541.         // Get filter name (converting BSTR name to a CString)
  542.         CString str(varName.bstrVal);
  543.         SysFreeString(varName.bstrVal);
  544.         nFilters++;
  545.  
  546.         // Read filter's CLSID from property bag.  This CLSID string will be
  547.         // converted to a binary CLSID and passed to AddFilter(), which will
  548.         // add the filter's name to the listbox and its CLSID to the listbox
  549.         // item's DataPtr item.  When the user clicks on a filter name in
  550.         // the listbox, we'll read the stored CLSID, convert it to a string,
  551.         // and use it to find the filter's filename in the registry.
  552.         VARIANT varFilterClsid;
  553.         varFilterClsid.vt = VT_BSTR;
  554.  
  555.         // Read CLSID string from property bag
  556.         hr = pPropBag->Read(L"CLSID", &varFilterClsid, 0);
  557.         if(SUCCEEDED(hr))
  558.         {
  559.             CLSID clsidFilter;
  560.  
  561.             // Add filter name and CLSID to listbox
  562.             if(CLSIDFromString(varFilterClsid.bstrVal, &clsidFilter) == S_OK)
  563.             {
  564.                 AddFilter(str, &clsidFilter);
  565.             }
  566.  
  567.             SysFreeString(varFilterClsid.bstrVal);
  568.         }
  569.        
  570.         // Cleanup interfaces
  571.         SAFE_RELEASE(pPropBag);
  572.         SAFE_RELEASE(pMoniker);
  573.     }
  574.  
  575.     // Update count of enumerated filters
  576.     SetNumFilters(nFilters);
  577.     return hr;
  578. }
  579.  
  580.  
  581. void CSysEnumDlg::OnSelchangeListFilters() 
  582. {
  583.     const CLSID *clsid;
  584.  
  585.     // Get the currently selected category name
  586.     int nItem = m_FilterList.GetCurSel();
  587.     
  588.     // Read the CLSID pointer from the list box's item data
  589.     clsid = (CLSID *) m_FilterList.GetItemDataPtr(nItem);
  590.  
  591.     // Find the filter filename in the registry (by CLSID)
  592.     if (clsid != 0)
  593.         ShowFilenameByCLSID(*clsid);
  594. }
  595.  
  596.  
  597. void CSysEnumDlg::ShowFilenameByCLSID(REFCLSID clsid)
  598. {
  599.     HRESULT hr;
  600.     LPOLESTR strCLSID;
  601.  
  602.     // Convert binary CLSID to a readable version
  603.     hr = StringFromCLSID(clsid, &strCLSID);
  604.     if(SUCCEEDED(hr))
  605.     {
  606.         TCHAR szKey[512];
  607.         CString strQuery(strCLSID);
  608.  
  609.         // Create key name for reading filename registry
  610.         wsprintf(szKey, TEXT("Software\\Classes\\CLSID\\%s\\InprocServer32\0"),
  611.                  strQuery);
  612.  
  613.         // Free memory associated with strCLSID (allocated in StringFromCLSID)
  614.         CoTaskMemFree(strCLSID);
  615.  
  616.         HKEY hkeyFilter=0;
  617.         DWORD dwSize=MAX_PATH;
  618.         BYTE pbFilename[MAX_PATH];
  619.         int rc=0;
  620.  
  621.         // Open the CLSID key that contains information about the filter
  622.         rc = RegOpenKey(HKEY_LOCAL_MACHINE, szKey, &hkeyFilter);
  623.         if (rc == ERROR_SUCCESS)
  624.         {
  625.             rc = RegQueryValueEx(hkeyFilter, NULL,  // Read (Default) value
  626.                                  NULL, NULL, pbFilename, &dwSize);
  627.  
  628.             if (rc == ERROR_SUCCESS)
  629.             {
  630.                 TCHAR szFilename[MAX_PATH];
  631.                 wsprintf(szFilename, TEXT("%s\0"), pbFilename);
  632.                 m_StrFilename.SetWindowText(szFilename);
  633.             }
  634.  
  635.             rc = RegCloseKey(hkeyFilter);
  636.         }
  637.     }
  638. }
  639.  
  640.  
  641. void CSysEnumDlg::OnClose() 
  642. {
  643.     // Free any stored CLSID pointers (in listbox item data ptr area)
  644.     ClearFilterList();
  645.     ClearDeviceList();
  646.  
  647.     // Release system device enumerator and close COM
  648.     SAFE_RELEASE(m_pSysDevEnum);
  649.     CoUninitialize();
  650.     
  651.     CDialog::OnClose();
  652. }
  653.  
  654.  
  655.